﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Happy.ExtentionMethods;
using Happy.Dto;
using Happy.Domain;

namespace Happy.Application.Domain
{
    /// <summary>
    /// 聚合根应用服务。
    /// </summary>
    public abstract class AggregateRootService<TAggregateRoot, TViewModel, TId, TUnitOfWork> : ApplicationService<TAggregateRoot, TId, TUnitOfWork>, IAggregateRootService<TViewModel>
        where TAggregateRoot : IAggregateRoot<TId>
        where TViewModel : IId<TId>, IOptimisticKey
        where TUnitOfWork : IUnitOfWork
    {
        #region 创建聚合根。

        /// <summary>
        /// 创建聚合根。
        /// </summary>
        public void Create(TViewModel viewModel)
        {
            var aggregate = this.CreateAggregate(viewModel);
            this.SaveAggregate(aggregate);
            this.SaveChanges();
            this.OnCreateSuccess(aggregate, viewModel);
        }

        /// <summary>
        /// 创建一个透明的聚合根。
        /// </summary>
        protected abstract TAggregateRoot CreateAggregate(TViewModel viewModel);

        /// <summary>
        /// 将聚合根保存到仓储中。
        /// </summary>
        protected virtual void SaveAggregate(TAggregateRoot aggregate)
        {
            this.Repository.Save(aggregate);
        }

        /// <summary>
        /// 修改视图信息以返回调用端需要的信息。
        /// </summary>
        protected virtual void OnCreateSuccess(TAggregateRoot aggregate, TViewModel viewModel)
        {
            viewModel.Id = aggregate.Id;
        }

        #endregion

        #region 修改聚合根

        /// <summary>
        /// 修改聚合根。
        /// </summary>
        public void Update(TViewModel viewModel)
        {
            var aggregate = this.LoadAggregate(viewModel.Id);
            this.CheckOptimisticConcurrency(aggregate, viewModel);
            this.UpdateAggregate(aggregate, viewModel);
            this.SaveChanges();
            this.OnUpdateSuccess(aggregate, viewModel);
        }
        /// <summary>
        /// 加载聚合根。
        /// </summary>
        protected virtual TAggregateRoot LoadAggregate(TId id)
        {
            return this.Repository.Load(id);
        }

        /// <summary>
        /// 执行乐观并发检查。
        /// </summary>
        protected virtual void CheckOptimisticConcurrency(TAggregateRoot aggregate, TViewModel viewModel)
        {
            aggregate.CheckConcurrent(viewModel.OptimisticKey);
        }

        /// <summary>
        /// 修改聚合根。
        /// </summary>
        protected abstract void UpdateAggregate(TAggregateRoot aggregate, TViewModel viewModel);

        /// <summary>
        /// 修改视图以返回调用端需要的信息。
        /// </summary>
        protected virtual void OnUpdateSuccess(TAggregateRoot aggregate, TViewModel viewModel)
        {
        }

        #endregion

        #region 删除聚合根

        /// <summary>
        /// 删除聚合根。
        /// </summary>
        public void Delete(TViewModel viewModel)
        {
            var aggregate = this.LoadAggregate(viewModel.Id);
            this.CheckOptimisticConcurrency(aggregate, viewModel);
            this.DeleteAggregate(aggregate);
            this.SaveChanges();
            this.OnDeleteSuccess(aggregate, viewModel);
        }

        /// <summary>
        /// 删除聚合根。
        /// </summary>
        protected virtual void DeleteAggregate(TAggregateRoot aggregate)
        {
            this.Repository.Delete(aggregate);
        }

        /// <summary>
        /// 修改命令以返回调用端需要的信息。
        /// </summary>
        protected virtual void OnDeleteSuccess(TAggregateRoot aggregate, TViewModel viewModel)
        {
        }

        #endregion
    }

    /// <summary>
    /// 聚合根应用服务。
    /// </summary>
    public abstract class AggregateRootService<TAggregateRoot, TViewModel, TUnitOfWork> : AggregateRootService<TAggregateRoot, TViewModel, Guid, TUnitOfWork>
        where TAggregateRoot : IAggregateRoot<Guid>
        where TViewModel : IId<Guid>, IOptimisticKey
        where TUnitOfWork : IUnitOfWork
    {
    }
}
